package com.example.score.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.score.common.Result;
import com.example.score.dto.ScoreLevel;
import com.example.score.dto.StudentScoreDto;
import com.example.score.dto.StudentScoreLevelDto;
import com.example.score.dto.StudentScoreLevelVo;
import com.example.score.entity.*;
import com.example.score.mapper.*;
import com.example.score.utils.CalculateQuestionNumUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/questions")
@RequiredArgsConstructor
public class QuestionController {

    private final QuestionInfoMapper questionInfoMapper;

    private final QuestionScoreMapper questionScoreMapper;

    private final ExamDetailMapper examDetailMapper;

    private final StudentSubmitMapper studentSubmitMapper;

    @GetMapping("/{examDetailId}")
    public List<QuestionInfo> getQuestions(@PathVariable Long examDetailId) {
        return questionInfoMapper.selectByExamDetailId(examDetailId);
    }

    /**
     * 获取小题分详情
     */
    @PostMapping("/getStudentQuestions")
    public Result<Map<String,Object>> getStudentQuestions(@RequestBody StudentScoreDto studentScoreDto) {
        ExamDetail examDetail = examDetailMapper.selectByExamId(studentScoreDto.getExamId());
        if(Objects.isNull(examDetail)){
            throw new RuntimeException("考试（作业）信息不存在！");
        }
        List<QuestionInfo> questionInfos = questionInfoMapper.selectByExamDetailId(examDetail.getId());
        if(CollectionUtils.isEmpty(questionInfos)){
            throw new RuntimeException("题目信息不存在！");
        }

        List<QuestionScore> studentQuestionScore =
                questionScoreMapper.getStudentQuestionScore(studentScoreDto.getStudentSubmitId(), examDetail.getId());
        if(CollectionUtils.isEmpty(studentQuestionScore)){
            throw new RuntimeException("题目得分不存在！");
        }
        Map<Long, QuestionScore> questionScoreMap = studentQuestionScore.stream().collect(Collectors
                .toMap(QuestionScore::getQuestionId, e ->e));

        //根据题型排序
        List<QuestionInfo> questionInfoSort = questionInfos.stream()
                .sorted(Comparator.comparing(QuestionInfo::getQuestionType).reversed())
                .collect(Collectors.toList());

        Map<String,Object> resultMap = new HashMap<>();
        for (QuestionInfo questionInfo : questionInfoSort) {
            String questionName = null;
            if(StringUtils.isNotEmpty(questionInfo.getQuestionAlias())){
                questionName = questionInfo.getQuestionTypeName() + "-" + questionInfo.getQuestionAlias();
            }else{
                Integer questionNum = questionInfo.getQuestionNum();
                int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionNum);
                int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionNum);
                if (smallQuestionNum != 0) {
                    questionName =   questionInfo.getQuestionTypeName() + bigQuestionNum + "-" +smallQuestionNum;
                } else {
                    questionName =  questionInfo.getQuestionTypeName() + "-" + bigQuestionNum;
                }
            }
            QuestionScore questionScore = questionScoreMap.get(questionInfo.getQuestionId());
            if(Objects.isNull(questionScore)){
                resultMap.put(questionName,null);
                continue;
            }
            Double score = questionScore.getScore();
            if("单选题".equals(questionInfo.getQuestionTypeName())){
                resultMap.put(questionName,score+"("+questionScore.getStudentAnswer()+")");
            }else{
                resultMap.put(questionName,score);
            }
        }

        return Result.success(resultMap);
    }

    /**
     * 获取区间分差值
     */
    @PostMapping("/getStudentScoreLevel")
    public Result<StudentScoreLevelVo> getStudentScoreLevel(@RequestBody StudentScoreLevelDto studentScoreLevelDto) {
        ExamDetail examDetail = examDetailMapper.selectByExamId(studentScoreLevelDto.getExamId());
        if(Objects.isNull(examDetail)){
            throw new RuntimeException("考试（作业）信息不存在！");
        }
        List<StudentSubmit> studentSubmits = studentSubmitMapper.selectByStudentSort(studentScoreLevelDto.getClassId(), examDetail.getId());
        if(Objects.isNull(studentSubmits)){
            throw new RuntimeException("考试（作业）信息不存在！");
        }
        //差值最高分
        int max = (int) Math.ceil(studentSubmits.get(0).getScore());
        //差值最低分
        int min = (int) Math.ceil(studentSubmits.get(studentSubmits.size() - 1).getScore());

        StudentScoreLevelVo studentScoreLevelVo = new StudentScoreLevelVo();
        Map<String,Integer> resultMap = new HashMap<>();
        studentScoreLevelVo.setLevelMap(resultMap);

        //当前学生所在区间
        Integer studentLevel = -1;
        //如果总数小于10，只给一个区间
        if(studentSubmits.size() < 10 || max == min){
            String k = min+"~"+max;
            for (int i = 0; i < studentSubmits.size(); i++) {
                this.addCount(resultMap,k);
            }
            studentScoreLevelVo.setScoreAvgLevel(1);
            return Result.success(studentScoreLevelVo);
        }

        //区间宽度
        int intervalWidth = (int) Math.ceil((max - min) / 5.0);

        for (StudentSubmit studentSubmit : studentSubmits) {
            double score = studentSubmit.getScore();
            if (score < min + intervalWidth) {
                String k = min+"~"+(min + intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 1;
                }
            } else if (score < min + 2 * intervalWidth) {
                String k = min + intervalWidth +"~"+(min + 2 * intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 2;
                }
            } else if (score < min + 3 * intervalWidth) {
                String k = (min + 2 * intervalWidth) +"~"+(min + 3 * intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 3;
                }
            } else if (score < min + 4 * intervalWidth) {
                String k = (min + 3 * intervalWidth) +"~"+( min + 4 * intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 4;
                }
            }else if (score < min + 5 * intervalWidth) {
                String k = (min + 4 * intervalWidth) +"~"+( min + 5 * intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 5;
                }
            }
        }

        Map<String, Integer> sortedByStart = resultMap.entrySet()
                .stream()
                .sorted(Comparator.comparingInt(entry -> {
                    String key = entry.getKey();
                    return Integer.parseInt(key.split("~")[0]);
                }))
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new
                ));
        studentScoreLevelVo.setLevelMap(sortedByStart);
        studentScoreLevelVo.setScoreAvgLevel(studentLevel);
        return Result.success(studentScoreLevelVo);
    }

    /**
     * 获取平均区间分差值
     */
    @PostMapping("/getStudentScoreAvgLevel")
    public Result<StudentScoreLevelVo> getStudentScoreAvgLevel(@RequestBody StudentScoreLevelDto studentScoreLevelDto) {
        ExamDetail examDetail = examDetailMapper.selectByExamId(studentScoreLevelDto.getExamId());
        if(Objects.isNull(examDetail)){
            throw new RuntimeException("考试（作业）信息不存在！");
        }
        List<StudentSubmit> studentSubmits = studentSubmitMapper.selectByStudentSort(studentScoreLevelDto.getClassId(), examDetail.getId());
        if(Objects.isNull(studentSubmits)){
            throw new RuntimeException("考试（作业）信息不存在！");
        }

        //拿到平均分
        int avgScore = new Double(studentSubmits.stream().mapToDouble(StudentSubmit::getScore).average().orElse(0.0)).intValue();
        //先计算所有分数与平均分的差值
        List<Integer> avgDVs = studentSubmits.stream()
                .map(e -> (int) Math.ceil(Math.abs(e.getScore() - avgScore)))
                .sorted(Comparator.reverseOrder())
                .collect(Collectors.toList());

        //差值最高分
        int max = avgDVs.get(0);
        //差值最低分
        int min = avgDVs.get(avgDVs.size() - 1);

        StudentScoreLevelVo studentScoreLevelVo = new StudentScoreLevelVo();
        Map<String,Integer> resultMap = new HashMap<>();
        studentScoreLevelVo.setLevelMap(resultMap);

        //当前学生所在区间
        Integer studentLevel = -1;
        //如果总数小于10，只给一个区间
        if(studentSubmits.size() < 10 || max == min){
            String k = min+"~"+max;
            for (int i = 0; i < studentSubmits.size(); i++) {
                this.addCount(resultMap,k);
            }
            studentScoreLevelVo.setScoreAvgLevel(1);
            return Result.success(studentScoreLevelVo);
        }

        //区间宽度
        int intervalWidth = (int) Math.ceil((max - min) / 4.0);

        for (StudentSubmit studentSubmit : studentSubmits) {
            if (Math.abs(studentSubmit.getScore() - avgScore) < min + intervalWidth) {
                String k = min+"~"+(min + intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 1;
                }
            } else if (Math.abs(studentSubmit.getScore() - avgScore) < min + 2 * intervalWidth) {
                String k = min + intervalWidth +"~"+(min + 2 * intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 2;
                }
            } else if (Math.abs(studentSubmit.getScore() - avgScore) < min + 3 * intervalWidth) {
                String k = (min + 2 * intervalWidth) +"~"+(min + 3 * intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 3;
                }
            } else if (Math.abs(studentSubmit.getScore() - avgScore) < min + 4 * intervalWidth) {
                String k = (min + 3 * intervalWidth) +"~"+( min + 4 * intervalWidth);
                this.addCount(resultMap,k);
                if(Objects.equals(studentSubmit.getStudentId(), studentScoreLevelDto.getStudentId())){
                    studentLevel = 4;
                }
            }
        }

        Map<String, Integer> sortedByStart = resultMap.entrySet()
                .stream()
                .sorted(Comparator.comparingInt(entry -> {
                    String key = entry.getKey();
                    return Integer.parseInt(key.split("~")[0]);
                }))
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new
                ));
        studentScoreLevelVo.setLevelMap(sortedByStart);
        studentScoreLevelVo.setScoreAvgLevel(studentLevel);
        return Result.success(studentScoreLevelVo);
    }


    public void addCount(Map<String,Integer> resultMap,String k){
        Integer count = resultMap.get(k);
        if(Objects.nonNull(count)){
            resultMap.put(k,count+1);
        }else{
            resultMap.put(k,1);
        }
    }
}
